﻿' ******************************************************************************
' ** 
' **  Yahoo! Managed
' **  Written by Marius Häusler 2011
' **  It would be pleasant, if you contact me when you are using this code.
' **  Contact: YahooFinanceManaged@gmail.com
' **  Project Home: http://code.google.com/p/yahoo-finance-managed/
' **  
' ******************************************************************************
' **  
' **  Copyright 2011 Marius Häusler
' **  
' **  Licensed under the Apache License, Version 2.0 (the "License");
' **  you may not use this file except in compliance with the License.
' **  You may obtain a copy of the License at
' **  
' **    http://www.apache.org/licenses/LICENSE-2.0
' **  
' **  Unless required by applicable law or agreed to in writing, software
' **  distributed under the License is distributed on an "AS IS" BASIS,
' **  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
' **  See the License for the specific language governing permissions and
' **  limitations under the License.
' ** 
' ******************************************************************************


Namespace YahooManaged.Finance

    ''' <summary>
    ''' Class for managing an International Securities Identification Number.
    ''' </summary>
    ''' <remarks></remarks>
    Public Class ISIN
        Private mChars(10) As Char
        Private mCheckDigit As Integer = -1
        Private ReadOnly mHelper As New MyHelper
        Private ReadOnly mFinanceHelper As New FinanceHelper
        Private mIsValid As Boolean = False

        ''' <summary>
        ''' The complete ISIN
        ''' </summary>
        ''' <value></value>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Public ReadOnly Property Value() As String
            Get
                Return mHelper.CharEnumToString(mChars) & Me.CheckDigit()
            End Get
        End Property

        ''' <summary>
        ''' The country specific part of the ISIN
        ''' </summary>
        ''' <value></value>
        ''' <returns>The first two letters if the ISIN is valid</returns>
        ''' <remarks></remarks>
        Public ReadOnly Property CountryCode() As String
            Get
                Return mChars(0) & mChars(1)
            End Get
        End Property

        ''' <summary>
        ''' The core part of the ISIN
        ''' </summary>
        ''' <value></value>
        ''' <returns>The ISIN without CountryCode and CheckDigit</returns>
        ''' <remarks></remarks>
        Public ReadOnly Property CoreCode() As String
            Get
                Return mChars(2) & mChars(3) & mChars(4) & mChars(5) & mChars(6) & mChars(7) & mChars(8) & mChars(9) & mChars(10)
            End Get
        End Property

        ''' <summary>
        ''' The calculated check digit of the ISIN
        ''' </summary>
        ''' <value></value>
        ''' <returns></returns>
        ''' <remarks>Every "get" call a calculation</remarks>
        Public ReadOnly Property CheckDigit() As Integer
            Get
                Return mCheckDigit
            End Get
        End Property

        ''' <summary>
        ''' Default constructor
        ''' </summary>
        ''' <param name="isinWithOrWithoutCheckDigit">A valid ISIN with or without check digit</param>
        ''' <remarks>If check digit exists, it will be ignored, but in this case the string must be a digit to be a valid ISIN. The check digit will be calculated seperatly.</remarks>
        Public Sub New(ByVal isinWithOrWithoutCheckDigit As String)
            If Not mFinanceHelper.IsIsinValidFormatted(isinWithOrWithoutCheckDigit) Then
                Throw New ArgumentException("The ISIN value is not valid formatted.", "isinWithOrWithoutCheckDigit")
            Else
                For i As Integer = 0 To 10
                    mChars(i) = Char.ToUpper(isinWithOrWithoutCheckDigit(i))
                Next

                Dim checkDigits As New List(Of Integer)
                For Each c As Char In mChars
                    Dim d As Integer = Me.CharToISINDigit(c)
                    checkDigits.AddRange(Me.ToSingleDigits(d))
                Next
                If checkDigits.Count > 0 Then
                    Dim quersumme As Integer = 0
                    Dim count As Integer = 1
                    For i As Integer = checkDigits.Count - 1 To 0 Step -1
                        count += 1
                        If count Mod 2 = 0 Then
                            checkDigits(i) *= 2
                        End If
                        Dim digits() As Integer = Me.ToSingleDigits(checkDigits(i))
                        For Each d As Integer In digits
                            quersumme += d
                        Next
                    Next
                    mCheckDigit = (10 - (quersumme Mod 10)) Mod 10
                Else
                    mCheckDigit = -1
                End If
            End If
        End Sub

        ''' <summary>
        ''' Returns the complete ISIN value.
        ''' </summary>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Public Overrides Function ToString() As String
            Return Me.Value
        End Function

        Private Function ToSingleDigits(ByVal i As Integer) As Integer()
            If i < 10 Then
                Return New Integer() {i}
            Else
                Dim db(1) As Integer
                db(0) = Convert.ToInt32(i.ToString()(0).ToString)
                db(1) = Convert.ToInt32(i.ToString()(1).ToString)
                Return db
            End If
        End Function
        Private Function CharToISINDigit(ByVal c As Char) As Integer
            If Char.IsDigit(c) Then
                Return Convert.ToInt32(c.ToString)
            Else
                Dim digit As Integer = 0
                For i As ISINDigits = ISINDigits.A To ISINDigits.Z
                    If c.ToString.ToUpper = i.ToString Then
                        digit = i
                        Exit For
                    End If
                Next
                Return digit
            End If
        End Function


        ''' <summary>
        ''' Checks a string for valid ISIN format
        ''' </summary>
        ''' <param name="isin">An ISIN with or without check digit</param>
        ''' <returns>True if ISIN is valid formatted</returns>
        ''' <remarks>If check digit exists, it will be ignored, but in this case the string must be a digit to be a valid ISIN. The check digit will be calculated seperatly.</remarks>
        Public Shared Function IsValidFormatted(ByVal isin As String) As Boolean
            Dim hlp As New FinanceHelper
            Return hlp.IsIsinValidFormatted(isin)
        End Function


        Private Enum ISINDigits
            A = 10
            B = 11
            C = 12
            D = 13
            E = 14
            F = 15
            G = 16
            H = 17
            I = 18
            J = 19
            K = 20
            L = 21
            M = 22
            N = 23
            O = 24
            P = 25
            Q = 26
            R = 27
            S = 28
            T = 29
            U = 30
            V = 31
            W = 32
            X = 33
            Y = 34
            Z = 35
        End Enum

    End Class

End Namespace